/* vim: set sw=8 ts=8 sts=8 expandtab: */
#include "Cmaid.h"
#include "cmaid_private.h"

/**
 * @defgroup Cmaid_Value The Value Definition Structure
 * @ingroup Misc
 *
 * The value structure and the related functions are describing how to
 * treat the data added to a container. It's like a interface for the
 * data, with the difference that it is not bundled with the data directly.
 */

/**
 * @brief The value structure for a pointer
 *
 * This value can be used for simple pointers, the data of the pointer doesn't
 * matter. It will not touch it.
 */
const Cmaid_Value cmaid_value_pointer =
{
        NULL, NULL, 0,
        {NULL, NULL, NULL},
        {NULL, NULL},
        NULL
};

/**
 * @brief The value for inline strings
 *
 * This value can be used for strings the string will be saved inside of the
 * node memory and thus will only need one allocation.
 */
const Cmaid_Value cmaid_value_inline_string =
{
        cmaid_value_string_compare, cmaid_value_string_hash, -1,
        {cmaid_value_string_size, NULL, NULL},
        {NULL, NULL},
        cmaid_value_string_stringify
};

/**
 * @brief The value for const strings
 *
 * This value can be used for strings. the string will not be saved nor freed,
 * anywhere, thus the strings need to be const or at least valid for the time
 * they are used in cmaid.
 */
const Cmaid_Value cmaid_value_const_string =
{
        cmaid_value_string_compare, cmaid_value_string_hash, 0,
        {NULL, NULL, NULL},
        {NULL, NULL},
        cmaid_value_string_stringify
};

/**
 * @param key The value to generate a hash value for it
 * @param size A pointer to store the size of the data in
 * @brief Calculate a hash value for the given pointer
 *
 * This functions calculates the hash value of a pointer and stores @c 0 in
 * @p size.
 */
unsigned int 
cmaid_value_pointer_hash(const void *key, unsigned int *size)
{
#ifdef __LP64__
        unsigned long int val = (unsigned long int)key;

        *size = 0;
        return (unsigned int) ((val >> 32) ^ val);
#else
        *size = 0;
        return (unsigned int) key;
#endif
}

/**
 * @param key the string to generate a hash value for
 * @param len the place to store the length (including the @c '\\0')
 * @brief Calculate a hash value for the given string
 *
 * This functions calculates the hash value of a string and stores the length,
 * including the terminating NUL, in @p size.
 */
unsigned int
cmaid_value_string_hash(const void *key, unsigned int *len)
{
        unsigned int hash_num = 5381;
        const unsigned char *ptr;

        for (ptr = (const unsigned char *)key; *ptr; ptr++)
        {
                hash_num = (hash_num * 33) ^ *ptr;
        }

        hash_num &= 0x3ff;
        *len = ptr - (const unsigned char *)key + 1;
        return hash_num;
}

/**
 * @param key1 The first pointer
 * @param key2 The second pointer
 * @returns 0 if both are equal, < 0 if @p key1 is smaller then @p key2 else > 0
 * @brief Compares the two pointer
 *
 * This function returns a negative value if @p key1 is smaller then @p key2, if
 * both are equal zero will be returned, else a positive number.
 */
int
cmaid_value_pointer_compare(const void *key1, const void *key2)
{
        if (key1 == key2)
                return 0;
        else if (key1 < key2)
                return -1;
        else
                return 1;
}

/**
 * @param key1 The first string
 * @param key2 The second string
 * @returns 0 if both are equal, < 0 if @p key1 is smaller then @p key2 else > 0
 * @brief Compares the two strings
 *
 * This function returns a negative value if @p key1 is smaller then @p key2, if
 * both are equal zero will be returned, else a positive number.
 */
int
cmaid_value_string_compare(const void *key1, const void *key2)
{
        if (key1 == key2)
                return 0;

        return strcmp((const char *)key1, (const char *)key2);
}

/**
 * @param key The string to get the size
 * @return Returns the size needed to store the string
 * @brief Retrieve the size of a string
 *
 * Unlike @c strlen() this function is returning the length needed to store
 * a string, i.e. the length plus 1 for the NUL-termination.
 */
unsigned int
cmaid_value_string_size(const void *key)
{
        return strlen((const char *)key) + 1;
}

/**
 * @param key The pointer to stringify
 * @param buffer The buffer to write the string into
 * @param size The size of the buffer
 * @return Returns
 * @brief WRITEME
 *
 * WRITEME
 */
void
cmaid_value_pointer_stringify(const void *key, char *buffer, unsigned int size)
{
        snprintf(buffer, size, "%p", key);
}

/**
 * @param key The string to stringify
 * @param buffer The buffer to write the string into
 * @param size The size of the buffer
 * @return Returns
 * @brief WRITEME
 *
 * WRITEME
 */
void
cmaid_value_string_stringify(const void *key, char *buffer, unsigned int size)
{
        snprintf(buffer, size, "%s", (const char *)key);
}

void *
cmaid_value_string_dup(const void *key)
{
        return STRDUP(key);
}

void
cmaid_value_string_free(void *key)
{
        FREE(key);
}


